In [1]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
pd.options.mode.chained_assignment = None

The model in theory

We are going to use 4 features: The price itself and three extra technical indicators.

  • MACD (Trend)
  • Stochastics (Momentum)
  • Average True Range (Volume)

Functions

Exponential Moving Average: Is a type of infinite impulse response filter that applies weighting factors which decrease exponentially. The weighting for each older datum decreases exponentially, never reaching zero.

MACD: The Moving Average Convergence/Divergence oscillator (MACD) is one of the simplest and most effective momentum indicators available. The MACD turns two trend-following indicators, moving averages, into a momentum oscillator by subtracting the longer moving average from the shorter moving average.

Stochastics oscillator: The Stochastic Oscillator is a momentum indicator that shows the location of the close relative to the high-low range over a set number of periods.

Average True Range: Is an indicator to measure the volalitility (NOT price direction). The largest of:

  • Method A: Current High less the current Low
  • Method B: Current High less the previous Close (absolute value)
  • Method C: Current Low less the previous Close (absolute value)

Calculation:


In [2]:
def MACD(df,period1,period2,periodSignal):
    EMA1 = pd.DataFrame.ewm(df,span=period1).mean()
    EMA2 = pd.DataFrame.ewm(df,span=period2).mean()
    MACD = EMA1-EMA2
    
    Signal = pd.DataFrame.ewm(MACD,periodSignal).mean()
    
    Histogram = MACD-Signal
    
    return Histogram

def stochastics_oscillator(df,period):
    l, h = pd.DataFrame.rolling(df, period).min(), pd.DataFrame.rolling(df, period).max()
    k = 100 * (df - l) / (h - l)
    return k

def ATR(df,period):
    '''
    Method A: Current High less the current Low
    '''
    df['H-L'] = abs(df['High']-df['Low'])
    df['H-PC'] = abs(df['High']-df['Price'].shift(1))
    df['L-PC'] = abs(df['Low']-df['Price'].shift(1))
    TR = df[['H-L','H-PC','L-PC']].max(axis=1)
    return TR.to_frame()

Read data


In [3]:
df = pd.read_csv('BTCUSD.csv',usecols=[1,2,3,4])
df = df.iloc[::-1]
df["Price"] = (df["Price"].str.split()).apply(lambda x: float(x[0].replace(',', '')))
df["Open"] = (df["Open"].str.split()).apply(lambda x: float(x[0].replace(',', '')))
df["High"] = (df["High"].str.split()).apply(lambda x: float(x[0].replace(',', '')))
df["Low"] = (df["Low"].str.split()).apply(lambda x: float(x[0].replace(',', '')))


dfPrices = pd.read_csv('BTCUSD.csv',usecols=[1])
dfPrices = dfPrices.iloc[::-1]
dfPrices["Price"] = (dfPrices["Price"].str.split()).apply(lambda x: float(x[0].replace(',', '')))

In [4]:
dfPrices.head(2)


Out[4]:
Price
2031 6.10
2030 5.96

Plot


In [5]:
price = dfPrices.iloc[len(dfPrices.index)-60:len(dfPrices.index)].as_matrix().ravel()

Price


In [6]:
prices = dfPrices.iloc[len(dfPrices.index)-60:len(dfPrices.index)].as_matrix().ravel()
plt.figure(figsize=(25,7))
plt.plot(prices,label='Test',color='black')
plt.title('Price')
plt.legend(loc='upper left')
plt.show()


MACD


In [7]:
macd = MACD(dfPrices.iloc[len(dfPrices.index)-60:len(dfPrices.index)],12,26,9)

In [8]:
plt.figure(figsize=(25,7))
plt.plot(macd,label='macd',color='red')
plt.title('MACD')
plt.legend(loc='upper left')
plt.show()


Stochastics Oscillator


In [9]:
stochastics = stochastics_oscillator(dfPrices.iloc[len(dfPrices.index)-60:len(dfPrices.index)],14)

In [10]:
plt.figure(figsize=(14,7))
#First 100 points because it's too dense
plt.plot(stochastics[0:100],label='Stochastics Oscillator',color='blue')
plt.title('Stochastics Oscillator')
plt.legend(loc='upper left')
plt.show()


Average True Range


In [11]:
atr = ATR(df.iloc[len(df.index)-60:len(df.index)],14)

In [12]:
plt.figure(figsize=(21,7))
#First 100 points because it's too dense
plt.plot(atr[0:100],label='ATR',color='green')
plt.title('Average True Range')
plt.legend(loc='upper left')
plt.show()


Create complete DataFrame & Save Data


In [13]:
dfPriceShift = dfPrices.shift(-1)
dfPriceShift.rename(columns={'Price':'PriceTarget'}, inplace=True)

In [14]:
dfPriceShift.head(2)


Out[14]:
PriceTarget
2031 5.96
2030 5.87

In [15]:
macd = MACD(dfPrices,12,26,9)
macd.rename(columns={'Price':'MACD'}, inplace=True)

In [16]:
stochastics = stochastics_oscillator(dfPrices,14)
stochastics.rename(columns={'Price':'Stochastics'}, inplace=True)

In [17]:
atr = ATR(df,14)
atr.rename(columns={0:'ATR'}, inplace=True)

In [18]:
final_data = pd.concat([dfPrices,dfPriceShift,macd,stochastics,atr], axis=1)
# Delete the entries with missing values (where the stochastics couldn't be computed yet) because have a lot of datapoints ;)
final_data = final_data.dropna()

In [19]:
final_data.info()


<class 'pandas.core.frame.DataFrame'>
Int64Index: 2018 entries, 2018 to 1
Data columns (total 5 columns):
Price          2018 non-null float64
PriceTarget    2018 non-null float64
MACD           2018 non-null float64
Stochastics    2018 non-null float64
ATR            2018 non-null float64
dtypes: float64(5)
memory usage: 94.6 KB

In [20]:
final_data


Out[20]:
Price PriceTarget MACD Stochastics ATR
2018 4.33 4.27 -0.108534 0.000000 0.13
2017 4.27 4.41 -0.129960 0.000000 0.06
2016 4.41 4.22 -0.131112 8.536585 0.14
2015 4.22 4.39 -0.136443 0.000000 0.19
2014 4.39 4.36 -0.124504 10.059172 0.17
2013 4.36 4.27 -0.112344 8.284024 0.03
2012 4.27 4.42 -0.103831 2.958580 0.09
2011 4.42 5.01 -0.083986 11.834320 0.15
2010 5.01 5.03 -0.030560 46.745562 0.59
2009 5.03 4.77 0.010302 58.695652 0.02
2008 4.77 4.92 0.024012 42.635659 0.26
2007 4.92 4.96 0.043686 67.307692 0.15
2006 4.96 4.87 0.060021 91.358025 0.04
2005 4.87 4.86 0.065227 80.246914 0.09
2004 4.86 4.92 0.067506 79.012346 0.01
2003 4.92 4.70 0.072104 86.419753 0.06
2002 4.70 4.61 0.059911 59.259259 0.22
2001 4.61 4.82 0.044715 44.736842 0.09
2000 4.82 4.98 0.047610 72.368421 0.21
1999 4.98 4.99 0.059798 93.421053 0.16
1998 4.99 4.94 0.068083 93.442623 0.01
1997 4.94 4.93 0.069260 78.571429 0.05
1996 4.93 4.86 0.068016 76.190476 0.01
1995 4.86 4.83 0.060962 65.789474 0.07
1994 4.83 4.91 0.052687 57.894737 0.03
1993 4.91 4.89 0.051274 78.947368 0.08
1992 4.89 5.27 0.047828 73.684211 0.02
1991 5.27 5.38 0.070552 100.000000 0.38
1990 5.38 5.33 0.092306 100.000000 0.11
1989 5.33 5.34 0.101513 93.506494 0.05
... ... ... ... ... ...
30 4386.30 4260.00 192.850261 100.000000 475.50
29 4260.00 4090.20 181.045033 91.725087 311.00
28 4090.20 4145.10 152.190815 74.438881 402.00
27 4145.10 4064.30 128.194449 79.178177 264.10
26 4064.30 4002.50 98.500534 69.227829 151.10
25 4002.50 4074.00 66.988464 63.321865 137.10
24 4074.00 4129.10 44.693793 70.154817 540.00
23 4129.10 4325.20 28.381596 73.712183 192.70
22 4325.20 4351.50 26.899048 91.767718 277.80
21 4351.50 4341.70 23.699187 93.317972 183.80
20 4341.70 4331.80 16.771700 88.379364 120.40
19 4331.80 4383.80 7.410516 85.799896 100.70
18 4383.80 4587.10 1.067624 99.348619 219.50
17 4587.10 4569.00 7.916757 100.000000 307.50
16 4569.00 4718.20 7.945005 96.903866 160.00
15 4718.20 4904.90 15.164981 100.000000 182.00
14 4904.90 4534.40 29.900692 100.000000 266.70
13 4534.40 4595.00 9.427583 58.942819 568.50
12 4595.00 4200.40 -4.278960 65.658245 368.80
11 4200.40 4374.90 -45.452996 15.212420 549.50
10 4374.90 4589.10 -63.771060 31.683424 569.80
9 4589.10 4613.50 -62.465297 55.173882 270.00
8 4613.50 4305.80 -60.919365 58.637331 207.50
7 4305.80 4317.90 -83.027066 14.960965 579.10
6 4317.90 4232.10 -98.053561 16.678495 221.80
5 4232.10 4203.00 -114.524398 4.499645 349.20
4 4203.00 4142.90 -127.286833 0.369056 250.10
3 4142.90 3849.70 -139.107720 0.000000 322.90
2 3849.70 3238.10 -166.464362 0.000000 425.60
1 3238.10 3480.10 -226.572569 0.000000 711.00

2018 rows × 5 columns


In [21]:
final_data.to_csv('BTCUSD_TechnicalIndicators.csv',index=False)